// ommWithClient.cpp: implementation of the CommWithClient class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CommWithClient.h"
#include "ListeningSocket.h"
#include "ServerSocketThread.h"

#include "CommonLib\Packet.h"
#include "CommonLib\Guard.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CommWithClient::CommWithClient():
	m_pListeningSocket(NULL),
	m_pWnd(NULL)
{
}

CommWithClient::~CommWithClient()
{
}

CommWithClient * CommWithClient::m_pInstance = NULL;

CommWithClient * CommWithClient::Instance()
{
	if (m_pInstance == NULL)
	{
		m_pInstance = new CommWithClient;
	}

	return m_pInstance;
}

void CommWithClient::DeleteInstance()
{
	if (m_pInstance) delete m_pInstance;

	m_pInstance = NULL;
}

void CommWithClient::StartUp(int nPort)
{
	m_pListeningSocket = new CListeningSocket;
	VERIFY(m_pListeningSocket->Create(nPort));
	VERIFY(m_pListeningSocket->Listen());
}

void CommWithClient::ShutDown()
{
	Guard guard(&m_mutexThreads);
	m_pListeningSocket->Close();
	if (m_pListeningSocket) delete m_pListeningSocket;

	std::list<CServerSocketThread*>::const_iterator iter;
	for (iter = m_Threads.begin(); iter != m_Threads.end(); ++iter)
	{
		CServerSocketThread * pThread = *iter;
		pThread->PostThreadMessage(WM_APP_EXITSOCKETTHREAD, 0, 0);
		//2005-7-8
		pThread->SetbStop(true);
	}
	for (iter = m_Threads.begin(); iter != m_Threads.end(); ++iter)
	{
		CServerSocketThread * pThread = *iter;
		if(pThread){
			//	VERIFY(WaitForSingleObject(pThread->m_hThread, INFINITE) == WAIT_OBJECT_0);
			//	pThread->DeleteInstance();
		}
	}
	m_Threads.clear();
}

bool CommWithClient::SendTo(const Packet& packet, HANDLE hClient)
{
	Guard guard(&m_mutexThreads);

	bool bRet = false;

	std::list<CServerSocketThread*>::const_iterator iter;
	for (iter = m_Threads.begin();iter != m_Threads.end();++iter)
	{
		CServerSocketThread * pThread = *iter;
		if (pThread->m_hSocket  == (SOCKET)hClient)
		{
			Packet * pPacket = new Packet;
			*pPacket = packet;
			pThread->AddPacketToSend(pPacket);
			bRet = true;
			break;
		}
	}

	return bRet;
}

bool CommWithClient::Receive(Packet& packet, HANDLE hClient)
{
	Guard guard(&m_mutexThreads);

	bool bRet = false;

	std::list<CServerSocketThread *>::const_iterator iter;
	for (iter = m_Threads.begin();iter != m_Threads.end(); ++iter)
	{
		CServerSocketThread * pThread = *iter;
		if (pThread->m_hSocket == (SOCKET)hClient)
		{
			Packet * pPacket = pThread->TakePacketReceived();
			if (pPacket)
			{
				packet = *pPacket;
				delete pPacket;
				bRet = true;
			}
			else{
				TRACE0("CommWithClient::Receive -> pThread->TakePacketReceived() NULL ");
			}
			break;
		}
	}

	return bRet;
}

bool CommWithClient::PostNotification(UINT message, HANDLE hClient, DWORD dwIPAddr)
{
	//TRACE1("PostNotification message=%d hClient=%x  ", message, hClient);
	if (m_pWnd && IsWindow(m_pWnd->GetSafeHwnd()))
	{
		//TRACE("PostNotification ok\n");
		return m_pWnd->PostMessage(message, dwIPAddr, (LPARAM)hClient);
	}
	else
	{
		TRACE("PostNotification false\n");
		return false;
	}
}

bool CommWithClient::SendNotification(UINT message, HANDLE hClient, DWORD dwIPAddr)
{
	if (m_pWnd && IsWindow(m_pWnd->GetSafeHwnd()))
	{
		return m_pWnd->SendMessage(message, dwIPAddr, (LPARAM)hClient);
	}
	else
	{
		return false;
	}
}

void CommWithClient::DeleteThreadBySocket(HANDLE hSocket)
{
	Guard guard(&m_mutexThreads);

	std::list<CServerSocketThread *>::const_iterator iter;
	for (iter = m_Threads.begin();iter != m_Threads.end();++iter)
	{
		CServerSocketThread * pThread = *iter;
		if (pThread->IsSocketHandleMatched((SOCKET)hSocket))
		{
			pThread->PostThreadMessage(WM_APP_EXITSOCKETTHREAD, 0, 0);
			VERIFY(WaitForSingleObject(pThread->m_hThread, INFINITE) == WAIT_OBJECT_0);
			m_Threads.erase(std::remove(m_Threads.begin(), m_Threads.end(), pThread), m_Threads.end());
			pThread->DeleteInstance();
			break;
		}
	}
}